package com.xuecheng.search.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.xuecheng.commons.enums.ErrorCode;
import com.xuecheng.commons.model.dto.CoursePubIndexDto;
import com.xuecheng.commons.model.dto.PageRequest;
import com.xuecheng.commons.model.vo.CoursePubIndexVo;
import com.xuecheng.commons.model.vo.CoursePubVo;
import com.xuecheng.commons.model.vo.PageResponseResult;
import com.xuecheng.commons.model.vo.ResponseResult;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.api.ContentClient;
import com.xuecheng.search.domain.CoursePubIndex;
import com.xuecheng.search.service.SearchService;
import com.xuecheng.web.exception.BusinessException;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

@Service
public class SearchServiceImpl implements SearchService {
    //数据同步

    @Autowired
    private ContentClient contentClient;

    @Autowired
    private RestHighLevelClient client;

    @Override
    public void MysqlToES(Long coursePubId) {
        // 1.feign调用查询课程发布对象
        ResponseResult<CoursePubVo> responseResult = contentClient.findById(coursePubId);
        if (responseResult.getCode() != 0) { // 调用失败
            throw new BusinessException(ErrorCode.NOTFOUND);
        }
        CoursePubVo coursePubVo = responseResult.getData();
        // 2.转成索引实体类
        CoursePubIndex coursePubIndex = BeanHelper.copyProperties(coursePubVo, CoursePubIndex.class);
        coursePubIndex.setIs_pub(coursePubVo.getIsPub());
        coursePubIndex.setCourse_id(coursePubVo.getCourseId());
        coursePubIndex.setIs_latest(coursePubVo.getIsLatest());
        coursePubIndex.setCreate_date(new Date());
        coursePubIndex.setCompany_id(coursePubVo.getCompanyId());
        coursePubIndex.setCompany_name(coursePubVo.getCompanyName());
        coursePubIndex.setChange_date(new Date());
        coursePubIndex.setComment_num(0L); // 评论数量

        // 价格手动设置  单位分
        coursePubIndex.setPrice(coursePubVo.getPrice().floatValue()*100);

        // 3.保存ES
        // 3-1 创建request
        IndexRequest request = new IndexRequest("course").id(coursePubIndex.getId().toString());
        // 3-2 准备DSL
        request.source(JSON.toJSONString(coursePubIndex), XContentType.JSON);
        // 3-3 发送请求
        try {
            client.index(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
    //条件分页查询
    @Override
    public ResponseResult<CoursePubVo> search(PageRequest pageRequest, CoursePubIndexDto dto) throws IOException {
    //创建SearchRequest
        SearchRequest request = new SearchRequest("course");
        buildDSL(pageRequest, dto, request);

        //发送请求
       SearchResponse response= client.search(request,RequestOptions.DEFAULT);
        return getResponseResult(response);
    }
    //删除数据
    @Override
    public void deleteES(Long coursePubId) {
    //创建删除文档请求
        DeleteRequest request = new DeleteRequest();

        //设置属性：指定要删除的索引及id值
        DeleteRequest delete = request.index("course").id(coursePubId.toString());
        try {
            //执行删除请求
            DeleteResponse deleteResponse = client.delete(delete, RequestOptions.DEFAULT);
        }catch (IOException e){
            e.printStackTrace();
        }


    }
    //根据id查询课程（免费、收费）
    @Override
    public ResponseResult<CoursePubIndexVo> findById(String id) throws IOException {
        // 1.创建GetReqeust
        GetRequest request = new GetRequest("course").id(id);
        // 2.发送请求
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        // 3.返回结果
        // 3-1 取出json
        String json = response.getSourceAsString();
        // 3-2 转vo
        CoursePubIndexVo vo = JSON.parseObject(json, CoursePubIndexVo.class);
        // 3-3 返回
        return ResponseResult.okResult(vo);

    }

    private static ResponseResult getResponseResult(SearchResponse response) {
        //解析结果并返回
        //取出命中结果
        SearchHits hits = response.getHits();
        //取出总记录数
        long total = hits.getTotalHits().value;
        //取出结果并遍历
        SearchHit[] searchHits = hits.getHits();
        //创建返回值vo集合
        ArrayList<CoursePubIndexVo> voList = new ArrayList<>();
        for (SearchHit searchHit : searchHits) {
            //获取原始json稳定的
            String json = searchHit.getSourceAsString();
            //转为java的vo对象
            CoursePubIndexVo coursePubIndexVo = JSON.parseObject(json, CoursePubIndexVo.class);
            //单独指定indexId
            coursePubIndexVo.setIndexId(coursePubIndexVo.getCourseId());

            //----------处理高亮 start
            // a）取出map
            Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
            // b）map非空判断
            if (CollectionUtil.isNotEmpty(highlightFields)) {
                // c）取出name数组
                HighlightField nameArray = highlightFields.get("name");
                // d）对name数组进行判断
                if (nameArray!=null) {
                    String name = nameArray.getFragments()[0].toString();
                    // e）将高亮设置到vo实体中
                    coursePubIndexVo.setName(name);
                }
            }

            //----------处理高亮 end

            //添加到集合中
            voList.add(coursePubIndexVo);
        }
        // 返回结果
        return PageResponseResult.okResult(total, voList);
    }

    private static void buildDSL(PageRequest pageRequest, CoursePubIndexDto dto, SearchRequest request) {
        //准备dsl
        //query查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //搜索 关键字是否为空
        if (StrUtil.isNotEmpty(dto.getKeyword())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("all", dto.getKeyword()));
        }else {
            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
        }

        // 条件过滤
        // 一级分类
        if (StrUtil.isNotEmpty(dto.getMt())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("mt", dto.getMt()));
        }
        // 二级分类
        if (StrUtil.isNotEmpty(dto.getSt())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("st", dto.getSt()));
        }
        // 课程等级
        if (StrUtil.isNotEmpty(dto.getGrade())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("grade", dto.getGrade()));
        }

        request.source().query(boolQueryBuilder);
        //分页
        Integer pageNo = pageRequest.getPageNo();
        Integer pageSize = pageRequest.getPageSize();
        Integer index=(pageNo-1)*pageSize;
        request.source().from(index).size(pageSize);
        // 2-3 高亮
        request.source().highlighter(new HighlightBuilder()
                .field("name")
                .preTags("<font style='color:red'>")
                .postTags("</font>")
                .requireFieldMatch(false));
    }
}

